from extends.db  import Base
from typing import List
from typing import Optional
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
from sqlalchemy import String, ForeignKey, Table, Column
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from typing import Dict, List


# 文档: https://docs.sqlalchemy.org/en/20/orm/basic_relationships.html#many-to-many
__all__ = ["User", "Power", "Role", "Address", "user_perm_list"]

user_perm_list: Dict[int, List[int]] = {}                
    
user_to_role = Table(
    "user_to_role",
    Base.metadata,
    Column("user_id", ForeignKey("user_account.id"), primary_key=True),
    Column("role_id", ForeignKey("role.id"), primary_key=True),
)

role_to_power = Table(
    "role_to_power",
    Base.metadata,
    Column("role_id", ForeignKey("role.id")),
    Column("power_id", ForeignKey("power.id")),
)

class Role(Base):
    """角色表
    """
    __tablename__ = "role"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(30))
    powers: Mapped[List["Power"]] = relationship(secondary=role_to_power, back_populates="roles")
    users: Mapped[List["User"]] = relationship(secondary=user_to_role, back_populates="roles")
    def __repr__(self) -> str:
        return f"Role(id={self.id!r}, name={self.name!r})"
    

class Power(Base):
    """权限表
    """
    __tablename__ = "power"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(30))
    roles: Mapped[List["Role"]] = relationship(secondary=role_to_power, back_populates="powers")


class User(Base):
    """用户表
    """
    __tablename__ = "user_account"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(30))
    fullname: Mapped[Optional[str]]
    addresses: Mapped[List["Address"]] = relationship(back_populates="user")
    roles: Mapped[List['Role']] = relationship(secondary=user_to_role, back_populates="users")

    def __repr__(self) -> str:
        return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"
    
    async def has_perm(self, power_name: str, session: AsyncSession) -> bool:
        # 查询是否存在指定权限
        query_power = select(Power).where(Power.name == power_name)
        res_power = await session.execute(query_power)
        power = res_power.scalar()
        
        if power is None:
            print("不存在的权限")
            return False

        # 在缓存里就返回
        if self.id in user_perm_list:
            return power.id in user_perm_list[self.id]

        # 查询用户及其角色和权限
        query_user = (
            select(User)
            .where(User.id == self.id)
            .options(selectinload(User.roles).selectinload(Role.powers))
        )
        res_user = await session.execute(query_user)
        user = res_user.scalar()

        if user is None:
            return False

        # 构建用户权限列表
        user_perm = [power.id for role in user.roles for power in role.powers]
        
        # 更新用户权限字典
        user_perm_list[self.id] = user_perm
        
        return power.id in user_perm
    

class Address(Base):
    """地址信息表
    """
    __tablename__ = "address"
    id: Mapped[int] = mapped_column(primary_key=True)
    email_address: Mapped[str]
    user_id = mapped_column(ForeignKey("user_account.id"))
    user: Mapped[User] = relationship(back_populates="addresses")
    def __repr__(self) -> str:
        return f"Address(id={self.id!r}, email_address={self.email_address!r})"